const { ccclass, property, menu, disallowMultiple, requireComponent } = cc._decorator;

@ccclass
@menu('ComponentExt/ScrollProgressBar')
@disallowMultiple
@requireComponent(cc.ProgressBar)
export class ScrollProgressBar extends cc.Component {

    /** ProgressBar 组件（可不填，初始化自动尝试获取当前节点的 ProgressBar 组件）*/
    @property(cc.ProgressBar)
    private scrollBar: cc.ProgressBar = null;

    @property(cc.Label)
    private readonly txtPrecent: cc.Label = null;


    // is updating
    private _isUpdate: boolean = false;

    // updating time precent
    private get timePct(): number {
        if (!this._timePct || this._timePct.end <= 0 || this._timePct.current < 0) return 0;
        return this._timePct.current / this._timePct.end;
    }
    // time update
    private timeUpdate(dt: number) {
        this._timePct.current += dt;
        // update precent
        if (!!this._value)
            this._value.current = this.deltaValue * this.timePct + this._value.from;
    }
    private _timePct: { current: number, end: number } = null;

    // LIFE-CYCLE CALLBACKS:

    /** 当前值，直接赋值会立即刷新当前值，不会进行滚动 */
    set value(v: number) {
        this._value.from = v;
        this._value.to = v;
        this._value.current = v;
        this.barPrecent = v;
    }
    get value() {
        return !this._value ? 0 : this._value.current;
    }
    // total value need change
    private get deltaValue() {
        return !this._value ? 0 : (this._value.to - this._value.from);
    }
    private _value: { from: number, to: number, current: number } = { from: 0, to: 0, current: 0 };

    /**
     * 滚动到目标值
     * @param duration 
     * @param target number | { from: number, to: number } 不传初始值，则默认从上次设置位置开始变化
     */
    scrollTo(duration: number, target: number | { from: number, to: number }) {
        if (duration <= 0) {
            this._isUpdate = false;
            this.value = typeof target == "number" ? target : target.to;
        } else {
            if (typeof target == "number") {
                this._value.to = target;
            } else {
                this._value.to = target.to;
                this._value.from = target.from;
                this._value.current = target.from;
            }
            this._timePct = { current: 0, end: duration };
            if (this._value.to !== this._value.from) {
                this.unschedule(this.endScroll);
                this._isUpdate = true;
                this.scheduleOnce(this.endScroll, duration);
            }
        }
    }
    private endScroll() {
        this._isUpdate = false;
        if (!!this._value) {
            this._value.from = this._value.to;
            this._value.current = this._value.to;
        }
        this.barPrecent = this.value;
        this._timePct = null;
    }

    /** node active */
    set active(b: boolean) {
        this.node.active = b;
    }
    get active(): boolean {
        return this.node.active;
    }


    onLoad() {
        if (!this.scrollBar)
            this.scrollBar = this.node.getComponent(cc.ProgressBar);
        this.value = 0;
    }

    onDestroy() {
        this.unschedule(this.endScroll);
    }

    protected update(dt: number) {
        if (!this._isUpdate || !this._value) return;

        if (this._value.current == this._value.to) {
            this.unschedule(this.endScroll);
            this.endScroll();
        } else {
            this.timeUpdate(dt);
            this.barPrecent = this.value;
        }
    }

    // set process bar display precent
    private set barPrecent(v: number) {
        if (!!this.scrollBar)
            this.scrollBar.progress = v;
        if (!!this.txtPrecent)
            this.txtPrecent.string = Math.round(v * 100) + "%"
    }
}
